package com.sky.service.impl;

import com.sky.dto.GoodsSalesDTO;
import com.sky.entity.Orders;
import com.sky.mapper.OrderMapper;
import com.sky.mapper.UserMapper;
import com.sky.service.ReportService;
import com.sky.service.WorkspaceService;
import com.sky.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Service;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j


public class ReportServiceImpl implements ReportService  {
    @Autowired
    private OrderMapper orderMapper ;
    @Autowired
    private UserMapper  userMapper ;
    @Autowired
    private WorkspaceService workspaceService;
    /**
     * 统计指定时间区间内的营业额数据
     * @param begin
     * @param end
     * @return
     */
    public TurnoverReportVO getTurnoverStatistics(@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin, @DateTimeFormat(pattern = "yyyy-MM-dd")LocalDate end){
        //当前集合用于存放begin到end范围内的每天的日期
        List<LocalDate > dateList =new ArrayList<>();
        dateList .add(begin );
        while(!begin.equals(end) ){
            //日起计算，计算指定日期的后一天
            begin =begin .plusDays(1);
            dateList .add(begin );
        }
        String string = StringUtils.join(dateList ,",");
        List<Double> turnoverList=new ArrayList<>();
        for (LocalDate localDate : dateList) {
            //查询date日期对应的营业额数据，营业额是指：状态为："已完成"的订单金额总计
            LocalDateTime beginTime=LocalDateTime .of(localDate , LocalTime .MIN );
            LocalDateTime endTime=LocalDateTime .of(localDate , LocalTime .MAX );
            //select sum(amount) from orders where order_time > ? and order_time<? and status=5
            Map map =new HashMap() ;
            map.put("begin",beginTime );
            map.put("end",endTime );
            map.put("status", Orders .COMPLETED );
            Double turnover= orderMapper.sumByMap(map);
            if(turnover ==null){
                turnover =0.0;
            }
            turnoverList .add(turnover );
        }
        return TurnoverReportVO
                .builder()
                .dateList(string)
                .turnoverList(StringUtils.join(turnoverList  ,","))
                .build() ;
    }
    /**
     * 统计指定时间区间内的用户数据
     * @param begin
     * @param end
     * @return
     */
    public UserReportVO getUserStatistics(@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin, @DateTimeFormat(pattern = "yyyy-MM-dd")LocalDate end){
        //存放从begin到end之间每天对应的日期
        List<LocalDate > dateList =new ArrayList<>();
        dateList .add(begin );
        while(!begin.equals(end) ){
            //日起计算，计算指定日期的后一天
            begin =begin .plusDays(1);
            dateList .add(begin );
        }
        //存放每天新增用户数量
        List<Integer > newUserList=new ArrayList<>();
        //存放每天总用户数量
        List<Integer > totalUserList=new ArrayList<>();
        for (LocalDate localDate : dateList) {
            //查询date日期对应的营业额数据，营业额是指：状态为："已完成"的订单金额总计
            LocalDateTime beginTime=LocalDateTime .of(localDate , LocalTime .MIN );
            LocalDateTime endTime=LocalDateTime .of(localDate , LocalTime .MAX );
            Map map=new HashMap<>();
            map.put("end",endTime );
            Integer totalUser=userMapper .countByMap(map) ;
            map.put("begin",beginTime );
            Integer newUser=userMapper .countByMap(map) ;
            totalUserList .add(totalUser );
            newUserList .add(newUser );
        }

        return UserReportVO .builder()
                .dateList(StringUtils .join(dateList ,",") )
                .totalUserList(StringUtils .join(totalUserList ,",") )
                .newUserList(StringUtils .join(newUserList ,",") )
                .build() ;
    }
    /**
     * 统计指定时间区间内的订单数据
     * @param begin
     * @param end
     * @return
     */
    public OrderReportVO getOrderStatistics(LocalDate begin, LocalDate end){
        //存放从begin到end之间每天对应的日期
        List<LocalDate > dateList =new ArrayList<>();
        dateList .add(begin );
        while(!begin.equals(end) ){
            //日起计算，计算指定日期的后一天
            begin =begin .plusDays(1);
            dateList .add(begin );
        }
        List<Integer > orderCountList=new ArrayList<>();
        List<Integer > validOrderCountList=new ArrayList<>();
        //遍历datelist集合，查询每天的有效订单数和订单总数
        for (LocalDate localDate : dateList) {
            LocalDateTime beginTime=LocalDateTime .of(localDate , LocalTime .MIN );
            LocalDateTime endTime=LocalDateTime .of(localDate , LocalTime .MAX );
            //查询每天的订单总数
            Integer orderCount=getOrderCount(beginTime ,endTime ,null);
            orderCountList .add(orderCount );
            //查询每天的有效订单数
            Integer validOrderCount=getOrderCount(beginTime ,endTime ,Orders .COMPLETED);
            validOrderCountList .add(validOrderCount );
        }
        //计算时间区间内的订单总数量
        Integer totalOrderCount=orderCountList .stream() .reduce(Integer::sum).get();
        //计算时间区间内的有效订单数量
        Integer validOrderCount=validOrderCountList.stream() .reduce(Integer::sum).get();
        Double orderCompletionRate=0.0;
        if(totalOrderCount !=0){
            //计算订单完成率
            orderCompletionRate=validOrderCount.doubleValue() /totalOrderCount;
        }


        return  OrderReportVO .builder()
                .dateList(StringUtils .join(dateList ,",") )
                .orderCountList(StringUtils .join(orderCountList ,",") )
                .validOrderCountList(StringUtils .join(validOrderCountList ,","))
                .totalOrderCount(totalOrderCount )
                .validOrderCount(validOrderCount )
                .orderCompletionRate(orderCompletionRate )
                .build() ;
    }

    /**
     * 根据条件统计订单数量
     * @param begin
     * @param end
     * @param status
     * @return
     */
    private Integer getOrderCount(LocalDateTime begin,LocalDateTime end,Integer status){
        Map map=new HashMap<>();
        map.put("begin",begin);
        map.put("end",end);
        map.put("status",status );
        return orderMapper.countByMap(map);
    }
    /**
     * 统计指定时间区间内的销量排名前10
     * @param begin
     * @param end
     * @return
     */
    public SalesTop10ReportVO getSalesTop10(LocalDate begin, LocalDate end){
        LocalDateTime beginTime=LocalDateTime .of(begin , LocalTime .MIN );
        LocalDateTime endTime=LocalDateTime .of(end , LocalTime .MAX );
        List<GoodsSalesDTO > salesTop10 = orderMapper .getSalesTop10(beginTime ,endTime );
        //select od.name ,sum(od.number) num  from order_detail od ,orders o where od.order_id=o.id and o.status=5 and o.order_time>'2024-8-1' and o.order_time<'2024-8-25' group by od.name order by num desc limit 0,10
        List<String > names=salesTop10.stream().map(GoodsSalesDTO ::getName ).collect(Collectors.toList() );
        String nameList=StringUtils .join(names,",");
        List<Integer> numbers=salesTop10 .stream() .map(GoodsSalesDTO ::getNumber ).collect(Collectors.toList()) ;
        String numberList=StringUtils .join(numbers ,",");

        return SalesTop10ReportVO .builder()
                .nameList(nameList )
                .numberList(numberList )
                .build() ;
    }
    /**
     * 导出运营数据报表
     * @param response
     */
    public void exportBusinessData(HttpServletResponse response)  {

        //1.查询数据库，获取营业数据
       LocalDate dateBegin= LocalDate.now().minusDays(30);
        LocalDate dateEnd= LocalDate.now().minusDays(1);
        //查询概览数据
        BusinessDataVO businessDataVO =workspaceService .getBusinessData(LocalDateTime.of(dateBegin ,LocalTime .MIN),LocalDateTime.of(dateEnd ,LocalTime .MAX)) ;
        //2.通过POI将数据写入到Excel文件中
        InputStream in = this.getClass().getClassLoader().getResourceAsStream("template/运营数据报表模板.xlsx");
        try {
            //基于模板创建一个新的Excel文件
            XSSFWorkbook excel = new XSSFWorkbook(in);
            //填充数据-时间
            XSSFSheet sheet = excel.getSheet("Sheet1");
            sheet.getRow(1).getCell(1).setCellValue("时间："+dateBegin +"至"+dateEnd);
            //获得第四行
            XSSFRow row = sheet.getRow(3);
            row.getCell(2).setCellValue(businessDataVO .getTurnover());
            row.getCell(4).setCellValue(businessDataVO .getOrderCompletionRate());
            row.getCell(6).setCellValue(businessDataVO .getNewUsers());

            //获得第5行
             row = sheet.getRow(4);
            row.getCell(2).setCellValue(businessDataVO .getValidOrderCount());
            row.getCell(4).setCellValue(businessDataVO .getUnitPrice());
            //填充明细数据
            for (int i=0;i<30;i++){
                LocalDate date=dateBegin .plusDays(i);
                BusinessDataVO businessData = workspaceService.getBusinessData(LocalDateTime.of(date, LocalTime.MIN), LocalDateTime.of(date, LocalTime.MAX));
                row = sheet.getRow(7 + i);
                row .getCell(1).setCellValue(date .toString());
                row.getCell(2).setCellValue(businessData .getTurnover());
                row.getCell(3).setCellValue(businessData .getValidOrderCount());
                row.getCell(4).setCellValue(businessData .getOrderCompletionRate());
                row.getCell(5).setCellValue(businessData .getUnitPrice());
                row.getCell(6).setCellValue(businessData .getNewUsers());
            }

            //3.通过输出流将Excel文件下载到客户端浏览器
            ServletOutputStream outputStream = response.getOutputStream();
            excel.write(outputStream );
            outputStream.close() ;
            excel .close() ;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }



    }
}
